{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "db789864",
   "metadata": {},
   "source": [
    "# 动静态图\n",
    "在这一节，我们学习一个很重要的内容，动态图和静态图。目前主流的深度学习框架有静态图`Graph`和动态图`PyNative`两种执行模式。\n",
    "![](./MindSpore架构.png)\n",
    "- 静态图模式下，程序在编译执行时，首先生成神经网络的图结构，然后再执行图中涉及的计算操作。因此，在静态图模式下，编译器可以通过使用图优化等技术来获得更好的执行性能，**有助于规模部署和跨平台运行**。\n",
    "\n",
    "\n",
    "- 动态图模式下，程序按照代码的编写顺序逐行执行，在执行正向过程中根据反向传播的原理，动态生成反向执行图。这种模式下，编译器将神经网络中的各个算子逐一下发到设备进行计算操作，**方便用户编写和调试神经网络模型**。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33862aaa",
   "metadata": {},
   "source": [
    "MindSpore提供了动态图和静态图统一的编码方式，仅变更一行代码便可切换静态图/动态图模式。动态图模式是MindSpore的默认模式，主要用于调试等用途，而静态图模式拥有更高效的执行性能，主要用于部署。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb803f09",
   "metadata": {},
   "source": [
    "## 模式切换\n",
    "配置context参数可以控制程序运行的模式。MindSpore处于静态图模式时，可以通过`ms.PYNATIVE_MODE`切换为动态图模式；同样，MindSpore处于动态图模式时，可以通过`ms.GRAPH_MODE`切换为静态图模式。注意：静态图模式下会有许多语法限制，而动态图模式下用户可以使用完整的Python API。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "5471d6f2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-11-16T08:07:38.601545Z",
     "start_time": "2022-11-16T08:07:38.578473Z"
    }
   },
   "outputs": [],
   "source": [
    "import mindspore as ms\n",
    "\n",
    "# 设置为静态图\n",
    "ms.set_context(mode=ms.GRAPH_MODE)\n",
    "\n",
    "# 设置为动态图\n",
    "ms.set_context(mode=ms.PYNATIVE_MODE)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b67fcbd9",
   "metadata": {},
   "source": [
    "## 静态图\n",
    "在MindSpore中，静态图模式又被称为Graph模式，比较适合网络固定且需要高性能的场景。在静态图模式下，基于图优化、计算图整图下沉等技术，编译器可以针对图进行全局的优化，因此在静态图模式下执行时**可以获得较好的性能**。但是，执行图是从源码转换而来，因此在静态图模式下**不是所有的Python语法都能支持，会有一些特殊的约束**。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "07809a6b",
   "metadata": {},
   "source": [
    "## 动态图\n",
    "当需要进行**调试，执行单算子、普通函数和网络、以及单独求梯度的操作**时，我们将使用动态图。在动态图模式下，**用户可以使用完整的Python API**。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0596fd18",
   "metadata": {},
   "source": [
    "## 动静结合\n",
    "MindSpore可以使用`ms.jit`装饰器来修饰需要用到静态图执行的对象，从而实现动静结合。2.0版本以前为`ms_function`。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8cf5feac",
   "metadata": {},
   "source": [
    "### 1、修饰独立函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fe9c2313",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-11-16T08:19:52.887193Z",
     "start_time": "2022-11-16T08:19:52.759543Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[5. 7. 9.]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import mindspore.ops as ops\n",
    "from mindspore import ms_function\n",
    "\n",
    "# 设置运行模式为动态图模式\n",
    "ms.set_context(mode=ms.PYNATIVE_MODE)\n",
    "\n",
    "# 使用装饰器，指定静态图模式下执行\n",
    "@ms_function\n",
    "def add_func(x, y):\n",
    "    return ops.add(x, y)\n",
    "\n",
    "x = ms.Tensor(np.array([1.0, 2.0, 3.0]).astype(np.float32))\n",
    "y = ms.Tensor(np.array([4.0, 5.0, 6.0]).astype(np.float32))\n",
    "\n",
    "out = add_func(x, y)\n",
    "print(out)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac1cd423",
   "metadata": {},
   "source": [
    "### 2、修饰成员函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5425bfb8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2022-11-16T08:21:05.472323Z",
     "start_time": "2022-11-16T08:21:05.281699Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Infer result:\n",
      " [5. 7. 9.]\n",
      "Gradient result:\n",
      "Grad x Tensor1:\n",
      " [1. 1. 1.]\n",
      "Grad y Tensor2:\n",
      " [1. 1. 1.]\n"
     ]
    }
   ],
   "source": [
    "import mindspore.nn as nn\n",
    "\n",
    "# 设置运行模式为动态图模式\n",
    "ms.set_context(mode=ms.PYNATIVE_MODE)\n",
    "\n",
    "class Add(nn.Cell):\n",
    "\n",
    "    @ms_function # 使用装饰器，指定静态图模式下执行\n",
    "    def construct(self, x, y):\n",
    "        out = x + y\n",
    "        return out\n",
    "\n",
    "x = ms.Tensor(np.array([1.0, 2.0, 3.0]).astype(np.float32))\n",
    "y = ms.Tensor(np.array([4.0, 5.0, 6.0]).astype(np.float32))\n",
    "\n",
    "grad_ops = ops.GradOperation(get_all=True)  # 定义求导操作\n",
    "net = Add()\n",
    "grad_out = grad_ops(net)(x, y)\n",
    "\n",
    "print(\"Infer result:\\n\", net(x, y))\n",
    "\n",
    "print(\"Gradient result:\")\n",
    "print(\"Grad x Tensor1:\\n\", grad_out[0])  # 对x求导\n",
    "print(\"Grad y Tensor2:\\n\", grad_out[1])  # 对y求导"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mindspore",
   "language": "python",
   "name": "mindvision"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
